package cn.tedu.review;
/*本类用于复写售票实现案例2*/

import jdk.nashorn.internal.ir.CatchNode;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestRunnable {
    public static void main(String[] args) {
        //4,创建自定义对象,作为唯一的业务对象
        TicketRunnable target = new TicketRunnable();
        //5,创建多个线程对象,并且把唯一的业务对象交给线程对象来干活
//        Thread t1 = new Thread(target);
//        Thread t2 = new Thread(target);
//        Thread t3 = new Thread(target);
//        Thread t4= new Thread(target);
        //6,以多线程的方式启动线程
//        t1.start();
//        t2.start();
//        t3.start();
//        t4.start();
        /*Executors是用来辅助创建线程池的工具类对象
        * 常用方法是newFixedThreadPool()这个方法可以创建指定数目的线程池对象
        * 创建出来的对象是ExecutorService:这个池子用来新建/启动/存储/销毁线程*/
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 5; i++) {
            /*execute()是让线程池中的线程来执行任务,每次调用这个方法
            * 都会将一个线程加入到就绪队列中,但注意,具体执行还得看OS是否选中*/
            pool.execute(target);/*本方法的参数就是我们的业务,也就有是业务类对象target                   */
        }

    }
}
/*1,多线程出现数据安全问题的原因:多线程程序+共享数据+多条语句操作共享数据
* 2,同步锁:相当于给容易出现问题的代码加了一把锁,包裹了所有可能会出现数据安全的代码
* 加锁之后,就有了同步(排队)的效果,加锁需要考虑:
* 锁的范围:不能太大,太大,干啥都得排队,效率低
*         不能太小,太小,锁不住,还是会出现安全隐患
* 并且注意!!!多个线程间,必须使用同一把锁,否则锁不住!!!*/
//1,自定义多线程售票类
class TicketRunnable implements Runnable{
    //3,完成业务
    int tickets=100;
   //Object o =new Object();
    //Cat c=new Cat();
    //2,添加接口中未实现的方法,里面是我们的业务
    @Override
    public void run() {
        while (true) {
            /*3,同步代码块:synchronized (唯一的锁对象){会出现安全隐患的所有代码}
             * 同步代码块在同一时刻,同一资源只会被一个线程对象独享*/
            /*这种写法不对,相当于每个线程进来时,执行这句话都会new一个新的锁对象
             * 多个线程间使用的并不是同一个唯一的锁对象,所以锁不住*/
            //synchronized(new Object())
            synchronized (TicketRunnable.class) {//同步代码块解决的是重卖的问题
                if (tickets > 0) {//如果有票就卖票
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + tickets--);
                }
                //7,让程序休眠,增加出错概率

                if (tickets <= 0) break;
            }
        }

    }
    }